#pragma once

#include "BoardItem.h"
#include "Board.h"
#include "Field.h"
#include "BuildPoint.h"
#include "Port.h"
#include "FieldResource.h"
#include "FieldDieNum.h"
#include "Player.h"
#include "Robber.h"
#include "Edge.h"
#include "DevelopmentCard.h"
#include "Edge.h"
#include "ResourceCard.h"
#include "Road.h"

namespace catan
{
	class BoardItems
	{
	public:
		friend class boost::archive::save_access;
		BoardItems(void);
		virtual ~BoardItems(void);

		void Remap();
 		template <class BoardItemType>
 		Handle<BoardItemType> ToHandle(BoardItemType* bit);

		template <class BoardItemType>
			BoardItemType* Get(HandleId id);
		
		typedef std::vector<BoardItem*> Datas;
		Datas mDatas;


		

		template <> Building* Get<Building>(HandleId id) 
		{ 
			if (mHouses.find(id) == mHouses.end())
			{
				return mSettlements[id];
			}
			else
			{
				return mHouses[id];
			}
		}

#define DefItem(BoardItemType) \
		template <> \
		Handle<BoardItemType> ToHandle<BoardItemType>(BoardItemType* bit) \
		{ \
			Handle<BoardItemType> ret(++mCreateId, bit); \
			m##BoardItemType##s[mCreateId] = bit; \
			mDatas.push_back(bit);\
			return ret; \
		} \
		std::map<HandleId, BoardItemType*> m##BoardItemType##s; \
		template <> BoardItemType* Get<BoardItemType>(HandleId id) \
		{ \
			if (m##BoardItemType##s.find(id) == m##BoardItemType##s.end()) \
			{\
				LogError(_T("no id") + FMTVAR(id));\
				VALID(0);\
			}\
			return m##BoardItemType##s[id]; \
		}

		DefItem(Board); 
		DefItem(Field);
		DefItem(BuildPoint);
		DefItem(Port);
		DefItem(DevelopmentCard);
		DefItem(FieldResource);
		DefItem(FieldDieNum);
		DefItem(Robber);
		DefItem(Edge);
		DefItem(ResourceCard);
		DefItem(Road);
		DefItem(Player);
		DefItem(House);
		DefItem(Settlement);
		DefItem(PlayerPack);

		int mCreateId;
		void Clear();

#undef DefItem

		template<class Serializer>
		void serialize(Serializer & s, const unsigned int version)
		{
#define DefItem(BoardItemType) \
	s & m##BoardItemType##s

			DefItem(Board); 
			DefItem(Field);
			DefItem(BuildPoint);
			DefItem(Port);
			DefItem(DevelopmentCard);
			DefItem(FieldResource);
			DefItem(FieldDieNum);
			DefItem(Robber);
			DefItem(Edge);
			DefItem(ResourceCard);
			DefItem(Road);
			DefItem(Player);
			DefItem(House);
			DefItem(Settlement);
			DefItem(PlayerPack);
#undef DefItem

		}
	};


// 
// 	class BoardItemFactory 
// 	{
// 	public:
// 		BoardItemFactory();
// 		~BoardItemFactory();
// 
// 		BoardItem* Create(TypeId)
// 		{
// 			CreateFacotrys::iterator it = mCreateFactorys.find(TypeId);
// 			if (it != mCreateFactorys.end())
// 			{
// 				return it->second->Create();
// 			}
// 			LogError("Create Failed");
// 			VALID(0);
// 			return NULL;	
// 		}
// 
// 		class ICreateFacotry
// 		{
// 			BoardItem* Create() = 0;
// 		};
// 
// 		template<class BoardItemType>
// 		class CreateFacotryTmpl
// 		{
// 			BoardItem* Create()
// 			{
// 				return new BoardItemType();
// 			}
// 		};
// 
// 		typedef std::map<TypeId mTypeId, ICreateFacotry*> CreateFacotrys;
// 		CreateFacotrys mCreateFactorys;
// 	}
// 	
	
}	

namespace boost {
	namespace serialization {


		using namespace catan;
		template<class Archive>
		void save(Archive & ar, const Handle<catan::Board>& b, const unsigned int version)
		{
			ar << b->mBoardItems;

			ar << b.Id();
			//ar << *b;
		}

		template<class Archive>
		void load(Archive & ar, Handle<catan::Board>& b, const unsigned int version)
		{
			BoardItems* items;
			ar >> items;
			items->Remap();
			HandleId id;
			ar >> id;
			b = Handle<Board>(id, items->Get<catan::Board>(id));
			b->mBoardItems = items;
		
			//ar >> *b;

		}

		template<class Archive>
		void serialize(
			Archive & ar,
			Handle<catan::Board> & t,
			const unsigned int file_version
			){
				split_free(ar, t, file_version); 
		}

		//BOOST_SERIALIZATION_SPLIT_FREE(catan::Handle<catan::Board>)


	} // namespace serialization
} // namespace boost